﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using InterfacesRegconition;
using System.IO;
using System.Reflection;
using DTO;

namespace RegconitionHost
{
    public partial class RegconitionHost : UserControl, IRegconitionHost
    {
        public RegconitionHost()
        {
            InitializeComponent();
        }

        #region Feature Vector Calculator
        public void FeedBack(string feedBackStr, IFeatureVectorCalculator pluginInterface)
        {
            //...
        }

        private Types.AvailableFeatureVectorCalculatorCollection availFVCPluginList = new Types.AvailableFeatureVectorCalculatorCollection();

        public Types.AvailableFeatureVectorCalculatorCollection AvailFVCPluginList
        {
            get { return availFVCPluginList; }
            set { availFVCPluginList = value; }
        }

        private void AddFVCPlugin(string fileName)
        {
            FileInfo fi = new FileInfo(fileName);
            if (fi.Extension.Equals(".dll"))
            {
                try
                {
                    Assembly pluginAssembly = Assembly.LoadFrom(fileName);

                    foreach (Type pluginType in pluginAssembly.GetTypes())
                    {
                        if (pluginType.IsPublic)
                        {
                            if (!pluginType.IsAbstract)
                            {
                                Type typeInterface = pluginType.GetInterface("InterfacesRegconition.IFeatureVectorCalculator", true);

                                if (typeInterface != null)
                                {
                                    Types.AvailableFeatureVectorCalculatorPlugin newPlugin = new Types.AvailableFeatureVectorCalculatorPlugin();

                                    newPlugin.MyAssemblyPath = fileName;

                                    newPlugin.MyInstance = (IFeatureVectorCalculator)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));

                                    newPlugin.MyInstance.PluginHost = this;

                                    newPlugin.MyInstance.Initialize();

                                    this.availFVCPluginList.Clear(); // Make sure there is just only one plugin at time
                                    this.availFVCPluginList.Add(newPlugin);

                                    newPlugin = null;
                                }

                                typeInterface = null;
                            }
                        }
                    }

                    pluginAssembly = null;
                }
                catch
                {
                    MessageBox.Show("Loading plugin dll failed!");
                }
            }
        }

        public void AddFVCPlugins(string[] fileNames)
        {
            foreach (string file in fileNames)
            {
                AddFVCPlugin(file);
            }

            if (availFVCPluginList.Count == 0)
            {
                MessageBox.Show("No plugin was load!");
            }
        }

        public void CloseAllFVCPlugin()
        {
            foreach (Types.AvailableFeatureVectorCalculatorPlugin plugin in availFVCPluginList)
            {
                plugin.MyInstance.PluginDispose();

                plugin.MyInstance = null;
            }

            availFVCPluginList.Clear();
        }

        public void FindFVCPlugins(string path)
        {
            availFVCPluginList.Clear();

            foreach (string file in Directory.GetFiles(path))
            {
                FileInfo fileInfo = new FileInfo(file);

                if (fileInfo.Extension.Equals(".dll"))
                {
                    this.AddFVCPlugin(file);
                }
            }
        }

        public void FindFVCPlugins()
        {
            FindFVCPlugins(AppDomain.CurrentDomain.BaseDirectory);
        }

        public void LoadFVCPlugins()
        {
            openFileDialog_LoadPlugin.Multiselect = true;
            openFileDialog_LoadPlugin.ShowDialog();

            if (openFileDialog_LoadPlugin.FileNames.Length != 0)
            {
                string[] selectedFiles = openFileDialog_LoadPlugin.FileNames;

                AddFVCPlugins(selectedFiles);
            }
        }
        #endregion

        #region Feature Vector Calculator Functions
        public Vector FeatureVectorCalculate(List<Vector> vectorList)
        {
            if (this.availFVCPluginList.Count != 0)
            {
                try
                {
                    return availFVCPluginList.Get(0).MyInstance.CalcFeatureVector(vectorList);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            else
            {
                throw new Exception("Feature Vector Calculator Plugin is not loaded!");
            }
        }

        #endregion

        #region GUI Event Handlers
        private void buttonClusteringPluginBrowse_Click(object sender, EventArgs e)
        {
            //openFileDialog_LoadPlugin.Multiselect = false;
            //openFileDialog_LoadPlugin.FileName = string.Empty;
            //openFileDialog_LoadPlugin.Filter = "Plugin (*.dll) |*.dll";
            //if (openFileDialog_LoadPlugin.ShowDialog() == DialogResult.OK)
            //{
            //    this.AddWGPlugins(openFileDialog_LoadPlugin.FileNames);

            //    if (availFVCPluginList.Count != 0)
            //    {
            //        this.textBoxClusteringPluginPath.Text = availFVCPluginList.Get(0).MyInstance.PluginName;
            //        this.groupBoxClusteringPluginConfiguration.Controls.Clear();
            //        this.groupBoxClusteringPluginConfiguration.Controls.Add(availFVCPluginList.Get(0).MyInstance.PluginUserControl);
            //    }
            //}
        }

        private void buttonVectorFileBrowse_Click(object sender, EventArgs e)
        {
            this.buttonClusterResultFile.Enabled = false;
            this.textBoxClusterResultFile.Text = string.Empty;

            openFileDialog_LoadPlugin.Multiselect = false;
            openFileDialog_LoadPlugin.FileName = string.Empty;
            openFileDialog_LoadPlugin.Filter = string.Empty;
            //openFileDialog_LoadPlugin.Filter = "Plugin (*.dll) |*.dll";
            if (openFileDialog_LoadPlugin.ShowDialog() == DialogResult.OK)
            {
                this.textBoxVectorFilePath.Text = openFileDialog_LoadPlugin.FileName;
                Global.vectorList = Vector.FromVectorFile(openFileDialog_LoadPlugin.FileName);
                foreach (Vector curVector in Global.vectorList)
                {
                    this.listBoxVector.Items.Clear();
                    string valueStr = curVector.ToString().Trim();
                    valueStr = valueStr.Replace(" ", " , ");
                    this.listBoxVector.Items.Add("(" + curVector.WebpageID + ")" + "  [ " + valueStr + " ]");
                    if (string.IsNullOrEmpty(this.textBoxTermFilePath.Text) == false)
                    {
                        this.buttonClusterResultFile.Enabled = true; 
                    }
                }
            }
        }

        private void buttonTermFileBrowse_Click(object sender, EventArgs e)
        {
            this.buttonClusterResultFile.Enabled = false;
            this.textBoxClusterResultFile.Text = string.Empty;

            openFileDialog_LoadPlugin.Multiselect = false;
            openFileDialog_LoadPlugin.FileName = string.Empty;
            openFileDialog_LoadPlugin.Filter = string.Empty;
            //openFileDialog_LoadPlugin.Filter = "Plugin (*.dll) |*.dll";
            if (openFileDialog_LoadPlugin.ShowDialog() == DialogResult.OK)
            {
                this.textBoxTermFilePath.Text = openFileDialog_LoadPlugin.FileName;
                Global.termList = Keyword.FromKeywordFile(openFileDialog_LoadPlugin.FileName);
                this.listBoxTerm.Items.Clear();
                foreach (Keyword curKeyword in Global.termList)
                {
                    this.listBoxTerm.Items.Add(curKeyword.KeywordText);
                }
                if (string.IsNullOrEmpty(this.textBoxVectorFilePath.Text) == false)
                {
                    this.buttonClusterResultFile.Enabled = true;
                }
            }
        }

        private void buttonFeatureVectorPluginBrowse_Click(object sender, EventArgs e)
        {
            openFileDialog_LoadPlugin.Multiselect = false;
            openFileDialog_LoadPlugin.FileName = string.Empty;
            openFileDialog_LoadPlugin.Filter = "Plugin (*.dll) |*.dll";
            if (openFileDialog_LoadPlugin.ShowDialog() == DialogResult.OK)
            {
                this.AddFVCPlugins(openFileDialog_LoadPlugin.FileNames);

                if (availFVCPluginList.Count != 0)
                {
                    this.textBoxFeatureVectorPluginPath.Text = availFVCPluginList.Get(0).MyInstance.PluginName;
                    this.groupBox_FVP.Controls.Clear();
                    availFVCPluginList.Get(0).MyInstance.PluginUserControl.Dock = DockStyle.Fill;
                    this.groupBox_FVP.Controls.Add(availFVCPluginList.Get(0).MyInstance.PluginUserControl);
                }
            }
        }

        private void buttonRunRegconition_Click(object sender, EventArgs e)
        {
            // Global.conceptList = this.availClusterPlugin.Get(0).MyInstance.FromVectorsToConcepts(Global.vectorList);
            if (this.availFVCPluginList.Count == 0)
            {
                MessageBox.Show("Feature Vector Calculator Plugin is not loaded");
                return;
            }

            List<Webpage> allWebpages = new List<Webpage>();
            try
            {
                allWebpages = DAL.WebpageDAL.GetWebpages();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }
            // make webpage dictionary
            Dictionary<int, Webpage> allWebpagesDict = new Dictionary<int, Webpage>();
            foreach (Webpage curWebpage in allWebpages)
            {
                allWebpagesDict.Add(curWebpage.ID, curWebpage);
            }

            this.treeViewConcept.Nodes.Clear();
            foreach (Concept curConcept in Global.conceptList)
            {
                TreeNode curTreeNode = new TreeNode("Concept " + curConcept.ID + " [ " + curConcept.WebpageInstanceVector.Count + " instance(s) ]");
                // calculate the feature vector
                curConcept.FeatureVector = this.availFVCPluginList.Get(0).MyInstance.CalcFeatureVector(curConcept.WebpageInstanceVector);

                string valueStr = curConcept.FeatureVector.ToString().Trim();
                valueStr = valueStr.Replace(" ", " , ");
                // add feature vector node
                curTreeNode.Nodes.Add(new TreeNode("Feature Vector [ " + valueStr + " ] "));
                // add instances node
                TreeNode instancesTreeNode = new TreeNode("Instances [ " + curConcept.WebpageInstanceVector.Count + " ] ");

                foreach (Vector curVector in curConcept.WebpageInstanceVector)
                {
                    Webpage curWebpage = allWebpagesDict[curVector.WebpageID];
                    instancesTreeNode.Nodes.Add(new TreeNode(" [" + curWebpage.ID + "] [ " + curWebpage.Title + " ] [ " + curWebpage.URL + "]"));
                }

                curTreeNode.Nodes.Add(instancesTreeNode);
                this.treeViewConcept.Nodes.Add(curTreeNode);
            }

            Concept.GetCandidates(Global.conceptList, Global.termList);
        }
        

        private void buttonClusterResultFile_Click(object sender, EventArgs e)
        {
            openFileDialog_LoadPlugin.Multiselect = false;
            openFileDialog_LoadPlugin.FileName = string.Empty;
            openFileDialog_LoadPlugin.Filter = string.Empty;
            //openFileDialog_LoadPlugin.Filter = "Plugin (*.dll) |*.dll";
            if (openFileDialog_LoadPlugin.ShowDialog() == DialogResult.OK)
            {
                this.textBoxClusterResultFile.Text = openFileDialog_LoadPlugin.FileName;
                Concept.FromClusterFile(Global.vectorList, this.textBoxClusterResultFile.Text);
                Global.conceptList = Concept.FromVectorsToConcept(Global.vectorList);
                
            }
        }

        private void buttonExport2XML_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog myFolderBrowseDlg = new FolderBrowserDialog();
            myFolderBrowseDlg.Description = "Choose the directory that will contain the exported xml file.";
            if (myFolderBrowseDlg.ShowDialog() == DialogResult.OK)
            {
                List<Webpage> allWebpagesList = DAL.WebpageDAL.GetWebpages();
                string filePath = myFolderBrowseDlg.SelectedPath;
                filePath += @"\" + "concept_" + DateTime.Now.ToString("MMM-d-yyyy HH-mm-ss") + ".xml"; 
                Concept.ToConceptFile(Global.conceptList,filePath,allWebpagesList);    
            }
            
        }
        #endregion
    }

    namespace Types
    {
        #region Feature Vector Calculator Types
        public class AvailableFeatureVectorCalculatorPlugin
        {
            private IFeatureVectorCalculator myInstance = null;

            public IFeatureVectorCalculator MyInstance
            {
                get { return myInstance; }
                set { myInstance = value; }
            }

            private string myAssemblyPath = string.Empty;

            public string MyAssemblyPath
            {
                get { return myAssemblyPath; }
                set { myAssemblyPath = value; }
            }

        }

        public class AvailableFeatureVectorCalculatorCollection : System.Collections.CollectionBase
        {
            public void Add(Types.AvailableFeatureVectorCalculatorPlugin plugin)
            {
                this.List.Add(plugin);
            }

            public void Remove(Types.AvailableFeatureVectorCalculatorPlugin plugin)
            {
                this.List.Remove(plugin);
            }

            public AvailableFeatureVectorCalculatorPlugin Get(int idx)
            {
                try
                {
                    return (AvailableFeatureVectorCalculatorPlugin)this.List[idx];
                }
                catch (IndexOutOfRangeException indexOutOfRangeEx)
                {
                    throw indexOutOfRangeEx;
                }
            }

            public AvailableFeatureVectorCalculatorPlugin Find(string pluginNameOrPath)
            {
                AvailableFeatureVectorCalculatorPlugin result = null;
                foreach (AvailableFeatureVectorCalculatorPlugin plugin in this.List)
                {
                    if ((plugin.MyInstance.PluginName.Equals(pluginNameOrPath))
                        || (plugin.MyAssemblyPath.Equals(pluginNameOrPath)))
                    {
                        result = plugin;
                        break;
                    }
                }

                return result;
            }
        }
        #endregion
    }
}